#pragma once
#include <string>
#include <iostream>
#include <assert.h>
#include <string.h>
#include <initializer_list>

namespace my_string
{
    using std::cout;
    using std::endl;

    // < threshold_sz 2倍增长，
    const size_t init_sz = 16;
    const size_t threshold_sz = 64;
    const size_t increase_sz = 32;

    class string
    {
    private:
        char *_str = nullptr;
        size_t _size = 0;
        size_t _capacity = 0;
        static const size_t npos;

    public:
        friend std::ostream &operator<<(std::ostream &out, string &str);
        friend std::istream &operator>>(std::istream &out, string &str);

        typedef char *iterator;
        typedef const char *const_iterator;

        void init()
        {
            _str = new char[init_sz]{0};
            _size = 0;
            _capacity = init_sz;
        }

        void addSpace(size_t len = 1)
        {
            size_t newcap = _size < threshold_sz ? 2 * _size + len : _size + len + increase_sz;
            char *tmp = new char[newcap]{0};
            // 在构造函数中我们调用了这个函数
            if (_str != nullptr)
            {
                strcpy(tmp, _str);
                delete _str;
                _str = tmp;
            }
            else
                _str = tmp;
            _capacity = newcap;
        }

        string()
        {
            init();
            cout << " string() " << endl;
        }

        string(const string &str, size_t pos, size_t len = npos)
        {
            addSpace(len);
            for (int i = pos; i < len && str[i] != '\0'; i++)
            {
                _str[_size++] = str[i];
            }
            cout << " string(const string &str, size_t pos, size_t len = npos) " << endl;
        }
        // 迭代器构造
        template <class InputIterator>
        string(InputIterator first, InputIterator last)
        {
            size_t len = 0;
            InputIterator tmp = first;
            while (tmp < last)
            {
                tmp++;
                len++;
            }
            addSpace(len);
            while (first < last)
            {
                _str[_size++] = *first;
                first++;
            }
            cout << " string(InputIterator first, InputIterator last) " << endl;
        }
        // string str = {'a','b','c'}
        string(std::initializer_list<char> il)
        {
            addSpace(il.size());
            int i = 0;
            for (auto ch : il)
            {
                _str[_size++] = ch;
            }
            cout << " string(std::initializer_list<char> il) " << endl;
        }
        // 拷贝构造
        string(const string &str)
        {
            _size = str.size();
            addSpace(_size);
            strcpy(_str, str._str);
            cout << " string(const string &str) " << endl;
        }
        // 移动构造
        string(string &&str)
        {
            swap(str);
            _size = str._size;
            _capacity = str._capacity;
            cout << "string(string &&str) " << endl;
        }

        void swap(string &str)
        {
            char *tmp = str._str;
            str._str = _str;
            _str = tmp;
        }

        string(const char *str)
        {
            *this += str;
            cout << "string(const char* str)" << endl;
        }

        iterator begin()
        {
            return _str;
        }
        iterator end()
        {
            return _str + _size;
        }

        const_iterator begin() const
        {
            return _str;
        }
        const_iterator end() const
        {
            return _str + _size;
        }

        void push_back(char c)
        {
            *this += c;
        }
        // abcd1111fg
        // abcdefg
        string &erase(size_t pos = 0, size_t len = npos)
        {
            if (len == 0)
                return *this;
            // 12abc5465
            // 12a546
            if (_size - len < _size && _size != len)
            {
                for (int i = pos + len; i < _size; i++)
                {
                    _str[i - len] = _str[i];
                }
                _size = _size - len;
                _str[_size] = 0;
            }
            else
            {
                _size = 0;
                _str[_size] = 0;
            }

            return *this;
        }
        // abcdefg
        // abcd1111fg
        //    pos + 1 向后偏移
        string &insert(size_t pos, const string &str)
        {
            int len = str.size();
            if (len == 0)
                return *this;
            if (_size + len > _capacity)
                addSpace(len);
            int n = _size;
            // 123465
            // 12abc5465
            for (int i = n - 1; i >= pos; i--)
            {
                _str[i + len] = _str[i];
            }
            for (int i = 0; i < len; i++)
            {
                _str[pos + i] = str[i];
            }
            _size += len;
        }

        // str += "124"
        string &operator+=(const string &str)
        {
            *this += str._str;
            return *this;
        }

        string &operator+=(const char *str)
        {
            int len = 0;
            while (str[len] != '\0')
                len++;
            if (_size + len >= _capacity)
                addSpace(len);
            for (int i = 0; i < len; i++)
            {
                _str[_size++] = str[i];
            }
            return *this;
        }
        string &operator+=(char ch)
        {
            if (_size >= _capacity)
                addSpace();
            _str[_size] = ch;
            _size++;
            return *this;
        }

        char &operator[](size_t pos)
        {
            assert(pos < _size);
            return _str[pos];
        }
        char &operator[](size_t pos) const
        {
            assert(pos < _size);
            return _str[pos];
        }

        size_t size() const
        {
            return _size;
        }

        bool empty() const
        {
            return _size == 0;
        }

        ~string()
        {
            delete _str;
            _size = 0;
            _capacity = 0;
        }
    };
    const size_t string::npos = -1;

    // cout << str1 << str2
    std::ostream &operator<<(std::ostream &out, string &str)
    {
        cout << str._str;
        return out;
    }
    // cin >> str
    std::istream &operator>>(std::istream &in, string &str)
    {
        str._size = 0;
        char ch;
        while (in >> ch)
        {
            if (ch == '\n')
                break;
            if (ch == ' ')
            {
                if (str.size() == 0)
                    continue;
                else
                    break;
            }
            str += ch;
        }
        return in;
    }
} // namespace my_vector
